/*
 * @Author: wwssaabb
 * @Date: 2021-12-08 16:07:41
 * @LastEditTime: 2021-12-08 16:59:18
 * @FilePath: \handwritten-code\promise\promise2.js
 */

import {
  reject
} from "../promise"

//三个状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
  constructor(executor) {
    //初始化状态
    this.state = PENDING
    this.value = null
    this.reason = null
    this.onFulfilledCallbacks = []
    this.onRejectedCallbacks = []

    try {
      executor(this.resolve, this.reject)
    } catch (error) {
      this.reject(error)
    }
  }

  resolve(value) {
    if (this.state === PENDING) {
      this.state = FULFILLED
      this.value = value
      while (this.onFulfilledCallbacks.length) this.onFulfilledCallbacks.pop()(value)
    }
  }

  reject(reason) {
    if (this.state === PENDING) {
      this.state = REJECTED
      this.reason = reason
      while (this.onRejectedCallbacks.length) this.onRejectedCallbacks.pop()(value)
    }
  }

  then(onFulfilled, onRejected) {
    //设置默认值
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
    onRejected = typeof onRejected === 'function' ? onRejected : reason => {
      throw new Error(reason)
    }

    //.then调用会注册微任务，使用queueMicrotask模拟
    const self = new MyPromise((resolve, reject) => {
      const fulfilledMicrotask = function () {
        queueMicrotask(() => {
          try {
            resolvePromise(onFulfilled, self, resolve, reject)
          } catch (error) {
            reject(error)
          }
        })
      }
      const rejectedMicrotask = function () {
        queueMicrotask(() => {
          try {
            resolvePromise(onRejected, self, resolve, reject)
          } catch (error) {
            reject(error)
          }
        })
      }

      if (this.state === FULFILLED) fulfilledMicrotask()
      if (this.state === REJECTED) rejectedMicrotask()
      if (this.state === PENDING) {
        this.onFulfilledCallbacks.push(fulfilledMicrotask)
        this.onRejectedCallbacks.push(rejectedMicrotask)
      }
      return self
    })
  }

  catch (onRejected) {
    this.then(undefined, onRejected)
  }
}

function resolvePromise(instance, self, resolve, reject) {
  if (instance === self) return new Error('')

  //instance为对象或函数的情况
  if (typeof instance === 'object' || typeof instance === 'function') {
    if (instance === null) return

    let then;
    try {
      then = instance.then
    } catch (error) {
      reject(error)
    }

    if (typeof instance === 'function') {
      let called = false

      try {
        then.call(instance, x => {
          if (called) return
          called = true
          resolvePromise(instance, x, resolve, reject)
        }, y => {
          if (called) return
          called = true
          resolvePromise(instance, y, resolve, reject)
        })
      } catch (error) {
        if (called) return
        called = true
        reject(error)
      }
    }
    resolve(instance)
  }

  if (instance instanceof MyPromise) {
    instance.then(resolve, reject)
  } else {
    resolve(instance)
  }
}